<template>
  <div class="container">
    <!-- 也不知道为什么，document挂载touchmove时间不响应，只能挂在overlay下 -->
    <van-overlay
      :class-name="'slidingPictures'"
      :show="visible"
      @touchmove="moveFunc"
    >
      <div class="sliding-pictures">
        <div class="vimg">
          <canvas id="sliderBlock"></canvas>
          <canvas id="codeImg"></canvas>
        </div>
        <div class="slider">
          <div class="track" :class="{ pintuTrue: puzzle }">
            {{ tips }}
          </div>
          <van-icon name="arrow" class="button" @touchstart.prevent="drag"/>
        </div>
        <div class="operation">
          <span
            title="关闭验证码"
            @click="visible = false"
            class="el-icon-circle-close"
          ></span>
          <span
            title="刷新验证码"
            @click="canvasInit"
            class="el-icon-refresh-left"
          ></span>
        </div>
      </div>
    </van-overlay>
  </div>
</template>

<script>
export default {
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    cb: {
      type: Function,
      default: function () {

      }
    }
  },
  data () {
    return {
      tips: '拖动左边滑块完成上方拼图',
      // 滑块x轴数据
      slider: {
        mx: 0,
        bx: 0
      },
      // 拼图是否正确
      puzzle: false,
      move: null
    }
  },
  watch: {
    visible (e) {
      if (e === true) {
        this.canvasInit()
        this.puzzle = false
      }
    }
  },
  mounted () {
    this.canvasInit()
    this.puzzle = false
    // this.$toast2({
    //   msg: '身份证未识别，为必传信息，请重新上传'
    // })
  },
  methods: {
    // 拼图验证码初始化
    canvasInit () {
      // 生成指定区间的随机数
      const random = (min, max) => {
        return Math.floor(Math.random() * (max - min + 1) + min)
      }
      // x: 254, y: 109
      const mx = random(127, 234)
      const bx = random(10, 97)
      const y = random(10, 99)

      this.slider = { mx, bx }

      this.draw(mx, bx, y)
    },
    moveFunc (e) {
      if (this.move) this.move(e)
    },
    draw (mx = 200, bx = 20, y = 50) {
      const mainDom = document.querySelector('#codeImg')
      const bg = mainDom.getContext('2d')
      const width = mainDom.width
      const height = mainDom.height

      const blockDom = document.querySelector('#sliderBlock')
      const block = blockDom.getContext('2d')
      // 重新赋值，让canvas进行重新绘制
      blockDom.height = height
      mainDom.height = height

      const imgsrc = require('@/assets/images/validate/back.jpg')
      const img = document.createElement('img')
      img.style.objectFit = 'scale-down'
      img.src = imgsrc
      img.onload = function () {
        bg.drawImage(img, 0, 0, width, height)
        block.drawImage(img, 0, 0, width, height)
      }

      const mainxy = { x: mx, y: y, r: 9 }
      const blockxy = { x: bx, y: y, r: 9 }
      this.drawBlock(bg, mainxy, 'fill')
      this.drawBlock(block, blockxy, 'clip')
    },
    // 绘制拼图
    drawBlock (ctx, xy = { x: 254, y: 109, r: 9 }, type) {
      const x = xy.x
      const y = xy.y
      const r = xy.r
      const w = 40
      const PI = Math.PI
      // 绘制
      ctx.beginPath()
      // left
      ctx.moveTo(x, y)
      // top
      ctx.arc(x + (w + 5) / 2, y, r, -PI, 0, true)
      ctx.lineTo(x + w + 5, y)
      // right
      ctx.arc(x + w + 5, y + w / 2, r, 1.5 * PI, 0.5 * PI, false)
      ctx.lineTo(x + w + 5, y + w)
      // bottom
      ctx.arc(x + (w + 5) / 2, y + w, r, 0, PI, false)
      ctx.lineTo(x, y + w)
      ctx.arc(x, y + w / 2, r, 0.5 * PI, 1.5 * PI, true)
      ctx.lineTo(x, y)
      // 修饰，没有会看不出效果
      ctx.lineWidth = 1
      ctx.fillStyle = 'rgba(255, 255, 255, 0.5)'
      ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)'
      ctx.stroke()
      ctx[type]()
      ctx.globalCompositeOperation = 'xor'
    },

    // 鼠标按下
    drag (e) {
      e.preventDefault()
      console.log(e)
      console.log(e.touches[0])
      // console.log("鼠标按下", e);
      const dom = e.target // dom元素
      const slider = document.querySelector('#sliderBlock') // 滑块dom
      const downCoordinate = { x: e.touches[0].pageX, y: e.touches[0].pageY }

      // 正确的滑块数据
      const checkx = Number(this.slider.mx) - Number(this.slider.bx)
      // x轴数据
      let x = 0
      this.move = moveEV => {
        moveEV.preventDefault()
        x = moveEV.touches[0].clientX - downCoordinate.x
        // const y = moveEV.y - downCoordinate.y
        if (x >= 251 || x <= 0) return false
        dom.style.left = x + 'px'
        // dom.style.top = y + "px";
        slider.style.left = x + 'px'
      }

      const up = e => {
        // console.log(e)
        // console.log(e.changedTouches[0].clientX)
        // console.log(downCoordinate.x)
        // console.log(e.changedTouches[0].clientX - downCoordinate.x, checkx)
        // document.removeEventListener('mousemove', move)
        // document.removeEventListener('mouseup', up)
        // document.removeEventListener('touchmove', move)
        this.move = null
        document.removeEventListener('touchend', up)
        dom.style.left = ''
        // 实际滑动会偏小，进行偏移
        const max = checkx - 5
        const min = checkx - 10
        // 采用点击距离和最终离开距离计算滑动距离
        const movex = e.changedTouches[0].clientX - downCoordinate.x
        console.log(max, movex, min)
        // 允许正负误差1
        if ((max >= movex && movex >= min) || movex === checkx) {
          console.log('滑动解锁成功')
          this.puzzle = true
          this.tips = '验证成功'
          setTimeout(() => {
            // if (this.cb) this.cb()
            this.$emit('ok')
          }, 300)
        } else {
          console.log('拼图位置不正确')
          this.tips = '验证失败，请重试'
          this.puzzle = false
          this.canvasInit()
        }
      }

      // document.addEventListener('touchmove', move)
      document.addEventListener('touchend', up)
    }
  }
}
</script>

<style lang="less" scoped>
/*该样式最终是以弹窗插入*/
.sliding-pictures {
  position: relative;
  top: 50%;
  padding: 0;
  width: 300px;
  border-radius: 2px;
  transform: translateY(-50%);
  background: #fff;
  margin: 0 auto;
  .vimg {
    width: 100%;
    height: 170px;
    #codeImg,
    #sliderBlock {
      padding: 7px 7px 0 7px;
      width: inherit;
      height: inherit;
    }
    #codeImg {
      //display: none;
    }
    #sliderBlock {
      position: absolute;
      z-index: 4000;
    }
  }
  .slider {
    width: 100%;
    height: 65px;
    border-bottom: #c7c9d0 1px solid;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    .track {
      margin-left: 7px;
      width: 286px;
      height: 38px;
      background: rgba(28, 136, 188, 0.5);
      border-radius: 25px;
      font-size: 14px;
      line-height: 38px;
      padding-right: 15px;
      padding-left: 70px;
    }
    .pintuTrue {
      background: #67c23a;
      color: #ffffff;
    }
    .button {
      position: absolute;
      width: 50px;
      height: 50px;
      line-height: 50px;
      background: #ffffff;
      box-shadow: #b9bdc8 0 0 3px;
      border-radius: 50%;
      left: 7px;
      text-align: center;
      font-size: 28px;
      color: #3e5d8b;
      border: 1px solid #ccc;
      &:hover {
        color: #2181bd;
      }
    }
  }
  .operation {
    width: 100%;
    height: 40px;
    > span {
      color: #9fa3ac;
      display: inline-block;
      width: 40px;
      font-size: 25px;
      line-height: 40px;
      text-align: center;
      &:hover {
        background: #e2e8f5;
      }
    }
  }
}
</style>
